package com.yami.shop.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.poi.excel.ExcelUtil;
import cn.hutool.poi.excel.ExcelWriter;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.yami.shop.bean.model.FlowPageAnalysis;
import com.yami.shop.bean.model.OrderItem;
import com.yami.shop.bean.param.*;
import com.yami.shop.common.exception.YamiShopBindException;
import com.yami.shop.common.util.Arith;
import com.yami.shop.common.util.DateUtils;
import com.yami.shop.common.util.PageParam;
import com.yami.shop.common.util.PoiExcelUtil;
import com.yami.shop.dao.FlowPageAnalysisMapper;
import com.yami.shop.dao.OrderMapper;
import com.yami.shop.dao.ProductMapper;
import com.yami.shop.service.FlowLogService;
import com.yami.shop.service.FlowPageAnalysisService;
import com.yami.shop.service.FlowProductAnalysisService;
import com.yami.shop.service.OrderItemService;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.poi.ss.usermodel.Sheet;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletResponse;
import java.util.*;

/**
 * 流量分析—页面数据统计表
 *
 * @author YXF
 * @date 2020-07-14 11:26:35
 */
@Service
@Slf4j
@AllArgsConstructor
public class FlowProductAnalysisServiceImpl implements FlowProductAnalysisService {

    private final OrderItemService orderItemService;
    private final FlowLogService flowLogService;
    private final ProductMapper productMapper;
    private final OrderMapper orderMapper;
    private final FlowPageAnalysisMapper flowPageAnalysisMapper;
    private final FlowPageAnalysisService flowPageAnalysisService;

    @Override
    public VisitorAndPayTopParam getPayAmountTop(PageParam<OrderItem> page, ProdAnalysisSurveyParam param) {
        IPage<PayTopParam> pages = orderItemService.getPayAmounts(page, param);
        VisitorAndPayTopParam res = new VisitorAndPayTopParam();
        List<PayTopParam> payTopParams = pages.getRecords();
        payTopParams.sort(Comparator.comparing(PayTopParam::getPayAmount).reversed());
        res.setPayAmounts(payTopParams);
        // 访客TOP
        IPage<FlowPageAnalysis> pageVisitor = new PageParam<>();
        pageVisitor.setSize(page.getSize());
        pageVisitor.setCurrent(page.getCurrent());
        pageVisitor.setPages(page.getPages());
        IPage<VisitorTopParam> visitorTops = flowPageAnalysisService.getVisitorTop(pageVisitor,param);
        List<VisitorTopParam> records = visitorTops.getRecords();
        if (CollectionUtils.isEmpty(records)) {
            return res;
        }
        for (VisitorTopParam record : records) {
            // 在筛选时间范围内，某件商品，有几个人支付
            Integer num = orderItemService.getPayPersonNumByParam(record.getProdId(),param.getShopId(),param.getStartTime(),param.getEndTime());
            record.setVisitorToPayRate(divAverage(num,record.getVisitorNum(),4));
        }
        records.sort(Comparator.comparing(VisitorTopParam::getVisitorNum).reversed());
        res.setVisitors(records);
        return res;
    }

    @Override
    public void payAmountTopExport(HttpServletResponse response, ProdAnalysisSurveyParam param) {
        PageParam<OrderItem> page = new PageParam<OrderItem>();
        page.setSize(10);
        page.setCurrent(1);
        VisitorAndPayTopParam payAmountTop = getPayAmountTop(page, param);
        //通过工具类创建writer
        ExcelWriter writer = ExcelUtil.getWriterWithSheet("支付金额TOP");
        // 商品导出or模板
        Sheet sheet = writer.getSheet();

        String[] header = {"店铺名称", "商品名称", "支付金额", "支付件数",};
        List<String> headerList = Arrays.asList(header);

        for (int i = 0; i < headerList.size(); i++) {
            sheet.setColumnWidth(i, 50 * 256);
        }
        writer.merge(headerList.size() - 1, "支付金额TOP");
        writer.writeRow(headerList);
        try {
            int row = 1;
            row = writerPayAmounts(writer, payAmountTop.getPayAmounts(), row);

            writer = writer.setSheet("访客数TOP");
            String[] visitorHeader = {"店铺名称","商品名称","访客数","访问-支付转化率"};
            List<String> visitorHeaderList = Arrays.asList(visitorHeader);
            Sheet visitorSheet = writer.getSheet();
            for (int i = 0; i < visitorHeaderList.size(); i++) {
                visitorSheet.setColumnWidth(i, 50 * 256);
            }
            writer.merge(visitorHeaderList.size() - 1, "访客数TOP");
            row = 1;
            writer.writeRow(visitorHeaderList);
            writerVisitor(writer, payAmountTop.getVisitors(), row);

            PoiExcelUtil.writeExcel(response, writer);
        } catch (Exception e) {
            log.error("导出支付金额TOP、访客数TOP:", e);
            throw new YamiShopBindException(e.getMessage());
        }
    }


    @Override
    public ProdAnalysisParam getProdSurvey(ProdAnalysisSurveyParam param) {
        flowLogService.insertBatch();
        ProdAnalysisParam analysisParam = new ProdAnalysisParam();
        ProdAnalysisRateParam rate = new ProdAnalysisRateParam();
        ProdAnalysisDataParam lastData;
        Integer dateType = param.getDateType();
        Date startTime = param.getStartTime();
        Date endTime = param.getEndTime();
        param.setDateTime(endTime);

        ProdAnalysisDataParam data = orderMapper.getProdSurvey(param);
        data.setCurrentDay(DateUtils.dateToStrYmd(param.getDateTime()));
//        // 新增商品数据
//        data.setNewProd(productMapper.countProdOnSale(param));
        param.setDateTime(null);
//        // 统计时间内销量不为零的商品数量
//        data.setDynamicSale(productMapper.countProdDynamicSale(param));
//        // 统计时间内，成功下单的商品件数之和（不剔除退款订单）
//        data.setOrderNum(setDefaultZero(orderMapper.countOrderNum(param)));
//        // 统计时间内， 成功付款订单的商品件数之和（不剔除退款订单）
//        data.setPayNum(setDefaultZero(orderMapper.countPayNum(param)));
        param.setDateTime(null);
        ProdAnalysisDataParam prodAnalysisDataParam;
        if (Objects.equals(1, dateType)) {
            // 今日实时
            prodAnalysisDataParam = flowLogService.getProdSurvey(param);
            data.setCurrentDay(DateUtil.format(new Date(),"yyyy-MM-dd HH:mm:ss"));
        } else {
            prodAnalysisDataParam = flowPageAnalysisMapper.getProdSurvey(param);
        }
        // 被访问商品数 统计时间内，商品详情页浏览次数大于 0 的商品数
        data.setVisitedProd(prodAnalysisDataParam.getVisitedProd());
        // 被访问商品数 统计时间内，商品详情页浏览次数大于 0 的商品数
        data.setBrowse(prodAnalysisDataParam.getBrowse());
        // 商品曝光数
        data.setExpose(prodAnalysisDataParam.getExpose());
        // 商品访客数
        data.setVisitor(prodAnalysisDataParam.getVisitor());
        // 统计时间内，添加商品进入购物车的商品件数
        data.setAddCart(prodAnalysisDataParam.getAddCart());
        // 统计时间内，分享访问次数
        data.setShareVisit(prodAnalysisDataParam.getShareVisit());
        if (!Objects.equals(1, dateType)) {
            // 统计时间前的数据-----------------------------------------------------------------------------------
            // 前多少天的数据
            Integer days = Integer.valueOf(String.valueOf(DateUtil.betweenDay(startTime, endTime, true))) + 1;
            param.setDateTime(DateUtils.getBeforeDay(startTime, -days));
            param.setStartTime(DateUtils.getBeforeDay(startTime, -days));
            param.setEndTime(DateUtil.offsetDay(endTime, -days));
            lastData = orderMapper.getProdSurvey(param);
//            lastData.setNewProd(productMapper.countProdOnSale(param));
//            lastData.setPayNum(setDefaultZero(orderMapper.countPayNum(param)));
//            lastData.setDynamicSale(productMapper.countProdDynamicSale(param));
//            lastData.setOrderNum(setDefaultZero(orderMapper.countOrderNum(param)));
            if(!Objects.isNull(lastData)){
                lastData.setCurrentDay(DateUtils.dateToStrYmd(startTime));
                ProdAnalysisDataParam lastProdAnalysisData = flowPageAnalysisMapper.getProdSurvey(param);
                lastData.setExpose(lastProdAnalysisData.getExpose());
                lastData.setVisitedProd(lastProdAnalysisData.getVisitedProd());
                lastData.setBrowse(lastProdAnalysisData.getBrowse());
                lastData.setAddCart(lastProdAnalysisData.getAddCart());
                lastData.setShareVisit(lastProdAnalysisData.getShareVisit());
                lastData.setVisitor(lastProdAnalysisData.getVisitor());
            }

            // 数据比例-----------------------------------------------------------------------------------
            if(!Objects.isNull(lastData)) {
                rate.setNewProdRate(divAverage(Arith.sub(data.getNewProd(), lastData.getNewProd()), lastData.getNewProd(), 4));
                rate.setDynamicSaleRate(divAverage(Arith.sub(data.getDynamicSale(), lastData.getDynamicSale()), lastData.getDynamicSale(), 4));
                rate.setOrderNumRate(divAverage(Arith.sub(data.getOrderNum(), lastData.getOrderNum()), lastData.getOrderNum(), 4));
                rate.setPayNumRate(divAverage(Arith.sub(data.getPayNum(), lastData.getPayNum()), lastData.getPayNum(), 4));
                rate.setVisitedProdRate(divAverage(Arith.sub(data.getVisitedProd(), lastData.getVisitedProd()), lastData.getVisitedProd(), 4));
                rate.setBrowseRate(divAverage(Arith.sub(data.getBrowse(), lastData.getBrowse()), lastData.getBrowse(), 4));
                rate.setExposeRate(divAverage(Arith.sub(data.getExpose(), lastData.getExpose()), lastData.getExpose(), 4));
                rate.setVisitorRate(divAverage(Arith.sub(data.getVisitor(), lastData.getVisitor()), lastData.getVisitor(), 4));
                rate.setAddCartRate(divAverage(Arith.sub(data.getAddCart(), lastData.getAddCart()), lastData.getAddCart(), 4));
                rate.setShareVisitRate(divAverage(Arith.sub(data.getShareVisit(), lastData.getShareVisit()), lastData.getShareVisit(), 4));
                rate.setShareVisitRate(divAverage(Arith.sub(data.getShareVisit(), lastData.getShareVisit()), lastData.getShareVisit(), 4));
            }
        } else {
            lastData = new ProdAnalysisDataParam();
        }
        // 数据回填-----------------------------------------------------------------------------------
        analysisParam.setData(data);
        analysisParam.setLastData(lastData);
        analysisParam.setRate(rate);
        return analysisParam;
    }

    @Override
    public void prodSurveyExport(HttpServletResponse response, ProdAnalysisSurveyParam param) {
        ProdAnalysisParam prodSurvey = getProdSurvey(param);
        //通过工具类创建writer
        ExcelWriter writer = ExcelUtil.getBigWriter();
        // 商品导出or模板
        Sheet sheet = writer.getSheet();

        String[] header = {"", "新增商品数", "被访问商品数", "动销商品数", "分享访问数", "商品浏览量", "商品访客数", "加购件数", "下单件数", "支付件数"};
        List<String> headerList = Arrays.asList(header);

        for (int i = 0; i < headerList.size(); i++) {
            sheet.setColumnWidth(i, 30 * 256);
        }

        writer.merge(headerList.size() - 1, "商品整体概况");
        writer.writeRow(headerList);

        try {
            int row = 1;
            int col = -1;
            // 当前数据
            ProdAnalysisDataParam data = prodSurvey.getData();
            PoiExcelUtil.mergeIfNeed(writer, ++row, row, ++col, col, "数量");
            PoiExcelUtil.mergeIfNeed(writer, row, row, ++col, col, data.getNewProd());
            PoiExcelUtil.mergeIfNeed(writer, row, row, ++col, col, data.getVisitedProd());
            PoiExcelUtil.mergeIfNeed(writer, row, row, ++col, col, data.getDynamicSale());
            PoiExcelUtil.mergeIfNeed(writer, row, row, ++col, col, data.getShareVisit());
            PoiExcelUtil.mergeIfNeed(writer, row, row, ++col, col, data.getBrowse());
            PoiExcelUtil.mergeIfNeed(writer, row, row, ++col, col, data.getVisitor());
            PoiExcelUtil.mergeIfNeed(writer, row, row, ++col, col, data.getAddCart());
            PoiExcelUtil.mergeIfNeed(writer, row, row, ++col, col, data.getOrderNum());
            PoiExcelUtil.mergeIfNeed(writer, row, row, ++col, col, data.getPayNum());

            col = -1;
            // 增长率
            ProdAnalysisRateParam rate = prodSurvey.getRate();
            PoiExcelUtil.mergeIfNeed(writer, ++row, row, ++col, col, "增长率");
            PoiExcelUtil.mergeIfNeed(writer, row, row, ++col, col, rate.getNewProdRate());
            PoiExcelUtil.mergeIfNeed(writer, row, row, ++col, col, rate.getVisitedProdRate());
            PoiExcelUtil.mergeIfNeed(writer, row, row, ++col, col, rate.getDynamicSaleRate());
            PoiExcelUtil.mergeIfNeed(writer, row, row, ++col, col, rate.getShareVisitRate());
            PoiExcelUtil.mergeIfNeed(writer, row, row, ++col, col, rate.getBrowseRate());
            PoiExcelUtil.mergeIfNeed(writer, row, row, ++col, col, rate.getVisitorRate());
            PoiExcelUtil.mergeIfNeed(writer, row, row, ++col, col, rate.getAddCartRate());
            PoiExcelUtil.mergeIfNeed(writer, row, row, ++col, col, rate.getOrderNumRate());
            PoiExcelUtil.mergeIfNeed(writer, row, row, ++col, col, rate.getPayNumRate());

            PoiExcelUtil.writeExcel(response, writer);
        } catch (Exception e) {
            log.error("导出商品概况:", e);
            throw new YamiShopBindException(e.getMessage());
        }
    }

    private int writerPayAmounts(ExcelWriter writer, List<PayTopParam> payAmounts, int row) {
        if (CollUtil.isEmpty(payAmounts)) {
            return row;
        }
        for (PayTopParam payAmount : payAmounts) {
            int col = -1;
            PoiExcelUtil.mergeIfNeed(writer, ++row, row, ++col, col, payAmount.getShopName());
            PoiExcelUtil.mergeIfNeed(writer, row, row, ++col, col, payAmount.getProdName());
            PoiExcelUtil.mergeIfNeed(writer, row, row, ++col, col, payAmount.getPayAmount());
            PoiExcelUtil.mergeIfNeed(writer, row, row, ++col, col, payAmount.getPayCount());
        }
        return row;
    }

    private void writerVisitor(ExcelWriter writer, List<VisitorTopParam> visitors, int row) {
        if (CollUtil.isEmpty(visitors)) {
            return;
        }
        for (VisitorTopParam visitor : visitors) {
            int col = -1;
            PoiExcelUtil.mergeIfNeed(writer, ++row, row, ++col, col, visitor.getShopName());
            PoiExcelUtil.mergeIfNeed(writer, row, row, ++col, col, visitor.getProdName());
            PoiExcelUtil.mergeIfNeed(writer, row, row, ++col, col, visitor.getVisitorNum());
            PoiExcelUtil.mergeIfNeed(writer, row, row, ++col, col, visitor.getVisitorToPayRate());
        }
    }

    private Double divAverage(Integer a, Integer b, Integer scale) {
        if (Objects.isNull(b) || b == 0 || Objects.isNull(a)) {
            return 0.0;
        }
        return Arith.div(a, b, scale);
    }
    private Double divAverage(Double a, Long b, Integer scale) {
        if (Objects.isNull(b) || b == 0 || Objects.isNull(a)) {
            return 0.0;
        }
        return Arith.div(a, b, scale);
    }

    private Double divAverage(Double a, Double b, Integer scale) {
        if (Objects.isNull(b) || b == 0 || Objects.isNull(a)) {
            return 0.0;
        }
        return Arith.div(a, b, scale);
    }

    public Integer setDefaultZero(Integer data) {
        if (Objects.isNull(data)) {
            return 0;
        }
        return data;
    }

    public Long setDefaultZero(Long data) {
        if (Objects.isNull(data)) {
            return 0L;
        }
        return data;
    }

}
